/* ******************************************************************************************************* */
/* ******************************** Computes CAR around shareholder meetings  ******************************/
/* ******************************************************************************************************* */

data permno_dates; set iss.Vote_Results2003_2018;

  if substr(issagendaitemid,1,1) = "S" then mgmt_sponsored = 0;
  if substr(issagendaitemid,1,1) = "M" then mgmt_sponsored = 1;

  if substr(issagendaitemid,1,1) = "S" then shrd_sponsored = 1;
  if substr(issagendaitemid,1,1) = "M" then shrd_sponsored = 0;


  if mgmtrec = issrec and mgmtrec in ("For", "Against") then issForMgmt=1; else 
  if mgmtrec ne issrec and mgmtrec in ("For", "Against") and issrec in ("For", "Against") then issForMgmt=0; else
  if (mgmtrec = "Abstain" or index(mgmtrec, "Do Not V") = 1) and issrec in ("Abstain", "Do Not Vote", "Withhold", "None") then issForMgmt=1; else
  if mgmt_sponsored = 1 and issrec in ("For") then issForMgmt=1; else
  if mgmt_sponsored = 1 and issrec in ("Do Not Vote") then issForMgmt=0; else
  if mgmtrec = "Withhold" and issrec in ("Abstain", "Do Not Vote", "Withhold") then issForMgmt=1; else
  if substr(upcase(mgmtrec), 1, 3) = substr(upcase(issrec), 1, 3) and index(upcase(mgmtrec), "YE") > 0 and index(upcase(issrec), "YE") > 0 then issForMgmt=1; else
  if substr(upcase(mgmtrec), 1, 3) ne substr(upcase(issrec), 1, 3) and index(upcase(mgmtrec), "YE") > 0 and index(upcase(issrec), "YE") > 0 then issForMgmt=0;

  turnout = (votedfor+votedagainst+votedabstain)/outstandingShare;
  if votedfor+votedagainst <= 1 then delete; *likely data errors;

proc freq data=permno_dates; tables VoteRequirement; run;

proc sort data = drop1.Proposal_list out = all_agenda nodupkey; by ISSAgendaItemID; 

proc sql;
  create table permno_dates as
  select a.*, b.issue
  from permno_dates as a, all_agenda as b
  where a.ISSAgendaItemID = b.ISSAgendaItemID; 
quit;

data permno_dates; set permno_dates;
  if index(ItemDesc, 'Elect Director') = 1 then delete;
  if index(ItemDesc, 'Elect  Directors') = 1 then delete;
  if VoteRequirement = 66.67 then VoteRequirement = .66;
  if VoteRequirement = .01 then VoteRequirement = .5; *fix data errors;
  if base in ('F+A', 'F A') then margin = votedfor/(votedfor+votedagainst)-voterequirement;
  if base in ('F+A+AB', 'F A AB') then margin = votedfor/(votedfor+votedagainst+votedabstain)-voterequirement;
  if base = 'Outstanding' then margin = votedfor/outstandingshare-voterequirement;
  if . < abs(margin) <= .2 then contested20 = 1; else if margin ne . then contested20 = 0;
  if . < abs(margin) <= .1 then contested10 = 1; else if margin ne . then contested10 = 0;
  if . < abs(margin) <= .05 then contested5 = 1; else if margin ne . then contested5 = 0;
  abs_margin = abs(margin);
  if voteresult = 'Pass' then pass = 1; else if voteresult = 'Fail' then pass = 0;

  if MGMTrec = 'Against' then do;
    if voteresult = 'Pass' then do; mgmt_win = 0; margin_mgmt = -abs(margin); end; else if voteresult = 'Fail' then do; mgmt_win = 1; margin_mgmt = abs(margin); end; end;
  if MGMTrec = 'For' then do;
    if voteresult = 'Pass' then do; mgmt_win = 1; margin_mgmt = abs(margin); end; else if voteresult = 'Fail' then do; mgmt_win = 0; margin_mgmt = -abs(margin); end; end;

  support = margin+voterequirement;
  if margin+voterequirement >= .95 then support_ge_95 = 1; else if margin+voterequirement ne . then support_ge_95 = 0; 
  if margin+voterequirement >= .99 then support_ge_99 = 1; else if margin+voterequirement ne . then support_ge_99 = 0; 

  if issformgmt = 1 then iss_win = mgmt_win; else if issformgmt = 0 then iss_win = 1-mgmt_win;
run;

proc sort data = permno_dates; by companyid meetingID meetingDate cusip ticker recordDate; 
  where issue ne '';

proc means data = permno_dates noprint; by companyid meetingID meetingDate cusip ticker recordDate; 
  var iss_win mgmt_win abs_margin; where contested20 = 0;
  output out = permno_dates1a (drop=_type_ _freq_) n(mgmt_win) = num_votes_nc mean = iss_win_nc mgmt_win_nc abs_margin sum(mgmt_win) = mgmt_win_nc_num; 

proc means data = permno_dates noprint; by companyid meetingID meetingDate cusip ticker recordDate; 
  var contested20 contested10 contested5 iss_win mgmt_win issForMgmt shrd_sponsored mgmt_sponsored;
  output out = permno_dates1b (drop=_type_ _freq_) n(mgmt_win) = num_votes sum = contested20 contested10 contested5 iss_win mgmt_win issForMgmt shrd_sponsored mgmt_sponsored; run;

proc means data = permno_dates noprint; by companyid meetingID meetingDate cusip ticker recordDate; 
  var turnout; where contested20 = 1;
  output out = permno_dates1c (drop=_type_ _freq_) mean = turnout_c; run;

data permno_dates1; merge permno_dates1a permno_dates1b permno_dates1c; by companyid meetingID meetingDate cusip ticker recordDate; 
  mgmt_lose_nc_num = num_votes_nc-mgmt_win_nc_num;

* add PERMNO - note obs with no match drop;;
proc sort data=crsp.stocknames(keep=permno ncusip cusip ticker namedt nameenddt shrcd exchcd siccd where=(not missing(ncusip))) 
  out=cusips nodupkey; by permno ncusip namedt nameenddt;
run;

proc sql;
  create table permno_dates2 as
  select a.*, b.permno, min(intck('month', b.namedt, a.meetingdate), intck('month', a.meetingdate, b.nameenddt)) as dist, b.siccd
  from permno_dates1 as a left join cusips as b
  on substr(a.cusip, 1, 8) = b.ncusip and b.namedt <= a.meetingdate <= nameenddt;
quit;

proc sort; by cusip meetingdate dist;

data permno_dates2; set permno_dates2; by cusip meetingdate dist;
  if first.meetingdate;

data permno_dates2a; set permno_dates2; 
  if dist ne .;

data permno_dates2; set permno_dates2; 
  if dist = .; 
  drop permno dist siccd;
run;

proc sql;
  create table permno_dates2 as
  select a.*, b.permno, min(intck('month', b.namedt, a.meetingdate), intck('month', a.meetingdate, b.nameenddt)) as dist, b.siccd
  from permno_dates2 as a left join cusips as b
  on substr(a.cusip, 1, 6) = substr(b.ncusip, 1, 6) and a.ticker = b.ticker and b.namedt <= a.meetingdate <= nameenddt;
quit;

data permno_dates2b; set permno_dates2; 
  if dist ne .;

data permno_dates2c; set permno_dates2; 
  if dist = .; 
  drop permno dist siccd;
run;

proc sql;
  create table permno_dates2x as
  select a.*, b.permno, min(abs(intck('month', b.namedt, a.meetingdate)), abs(intck('month', a.meetingdate, b.nameenddt))) as dist, b.siccd
  from permno_dates2c as a left join cusips as b
  on substr(a.cusip, 1, 8) = substr(b.ncusip, 1, 8); 
quit;

proc sort; by cusip meetingdate dist;

data permno_dates2c; set permno_dates2x; by cusip meetingdate dist;
  if first.meetingdate;
  if permno ne .; 
run;

data permno_dates3; set permno_dates2a (in=a) permno_dates2b (in=b) permno_dates2c (in=c);
  if a then s = 1; 
  if b then s = 2; 
  if c then s = 3; 

proc means n mean median p1 p99;
  var permno dist siccd;

data x2; set permno_dates3;
  if permno = 24046; 
run;

proc sort data=comp.funda (keep=gvkey cusip conm datadate datafmt indfmt popsrc consol fyear fyr sich naicsh fic xad cik act lct epspx emp
  che at dltt lt pstkl pstk sale oibdp dp ib dvc csho dlc txditc cogs xrd pstkrv ceq txdb dcvt lt xsga prcc_f ppent xint txt capx aqc curcd) out=funda nodupkey;
  where at > 0 and sale >= 0 and 2019 >= fyear >= 2001 and indfmt= 'INDL' and datafmt= 'STD' and popsrc= 'D' and consol= 'C' and curcd = 'USD'; 
  * retrieve accounting information as early as 1960 to calculate cash flow volatility over the past 20 years;
  by gvkey fyear;
run;

proc sql;
  create table permno_dates3 as
  select a.*, b.sich, intck('month', b.datadate, a.meetingdate) as int
  from permno_dates3 as a left join funda as b
  on a.cusip = b.cusip and 3 <= intck('month', b.datadate, a.meetingdate) <= 18;
quit;

proc sort; by cusip meetingdate int;

data permno_dates3; set permno_dates3; by cusip meetingdate int;
  if first.meetingdate;
  if sich = . and siccd ne 0 then sich = siccd;
/* Select Compustat's SICH as primary SIC code, if not available, then use CRSP's historical SICCD	 */

proc sql;
  create table permno_dates3 as
  select a.*, b.ff48, b.ff48ind
  from permno_dates3 as a left join root.ff48 as b
  on ff1 <= sich <= ff2;
quit;

proc means n mean median p1 p99;
  var permno dist siccd sich ff48;
run;



proc sort data = permno_dates3 out = temp.stock_meetings (keep=permno meetingdate sich ff48 num_votes_nc num_votes contested20 contested5 contested10 issForMgmt iss_win mgmt_win shrd_sponsored mgmt_sponsored iss_win_nc mgmt_win_nc mgmt_lose_nc_num turnout_c) nodupkey; by permno meetingdate; 
  where num_votes > 0;
run;

proc sql;
  create table stock_meetings2 as
  select a.permno, a.meetingdate, a.sich, a.ff48, b.date, b.ret, b.prc, b.cfacshr
  from temp.stock_meetings as a, crsp.dsf as b
  where a.permno = b.permno and -800 <= intck('day', b.date, a.meetingdate) <= 366+183;
quit;

proc sql;
  create table stock_meetings2 as
  select a.*, b.hml, b.smb, b.mktrf, b.umd, b.rf, a.ret-b.rf as retx, a.ret-b.rf-b.mktrf as ret_mktadj
  from stock_meetings2 as a, ff.factors_daily2020 as b
  where a.date = b.date;
quit;

proc contents data = stock_meetings2; run;

proc sort data = stock_meetings2 out = stock_meetings2a nodupkey; by permno meetingdate descending date; 
  where date < meetingdate;

data stock_meetings2a; set stock_meetings2a;
  by permno meetingdate descending date; 
  if first.meetingdate then td_count = 0;
  td_count = td_count-1; *increments in negative direction;
  retain td_count;

proc sort data = stock_meetings2 out = stock_meetings2b nodupkey; by permno meetingdate date;  
  where date >= meetingdate;

data stock_meetings2b; set stock_meetings2b;
  by permno meetingdate;
  if first.meetingdate then td_count = -1;
  td_count=td_count+1;    *increments in positive direction;
  retain td_count;

*** BETAs;
proc means data = stock_meetings2a noprint; by permno meetingdate;
  var ret; where -10-252 <= td_count < -10;
  output out = count (drop=_type_ _freq_) n = num_trdng_days_beta;
run;

proc reg data = stock_meetings2a noprint outest=mktbeta(keep=permno meetingdate intercept mktrf);
  by permno meetingdate; where -10-252 <= td_count < -10 and retx ne .;
  model retx = mktrf;

proc reg data = stock_meetings2a noprint outest=ff4beta(keep=permno meetingdate intercept mktrf smb hml umd); *;
  by permno meetingdate; where -10-252 <= td_count < -10 and retx ne .;
  model retx = mktrf smb hml umd; *;

data ff4beta; set ff4beta;
  alpha_ff4 = intercept; betam4 = mktrf; betas4 = smb; betah4 = hml; betau4 = umd;
  drop mktrf intercept;

proc reg data = stock_meetings2a noprint outest=ff3beta(keep=permno meetingdate intercept mktrf smb hml); *;
  by permno meetingdate; where -10-252 <= td_count < -10 and retx ne .;
  model retx = mktrf smb hml; *;

data ff3beta; set ff3beta;
  alpha_ff3 = intercept; betam3 = mktrf; betas3 = smb; betah3 = hml;
  drop mktrf intercept;

data stock_betas; merge mktbeta ff4beta ff3beta count; by permno meetingdate; 
  alpha_m = intercept; beta = mktrf;
  if beta ne .;
  keep permno meetingdate alpha_m beta alpha_ff3 betam3 betas3 betah3 alpha_ff4 betam4 betas4 betah4 betau4 num_trdng_days_beta; *;

proc means data = stock_betas n mean median p5 p95;

data price_pr2; set stock_meetings2a;
  if td_count = -2;
  prc_pr2 = abs(prc);
  cfacshr_pr2 = cfacshr;
  keep permno meetingdate prc_pr2 cfacshr_pr2;

proc sort; by permno meetingdate; 
run;


************************************************* Compute industry-adjusted returns *************************************************;
proc sort data=comp.funda (keep=gvkey cusip conm datadate datafmt indfmt popsrc consol fyear fyr sich naicsh fic xad cik act lct epspx emp
  che at dltt lt pstkl pstk sale oibdp dp ib dvc csho dlc txditc cogs xrd pstkrv ceq txdb dcvt lt xsga prcc_f ppent xint txt capx aqc curcd) out=cst nodupkey;
  where at > 0 and sale >= 0 and 2019 >= fyear >= 2001 and indfmt= 'INDL' and datafmt= 'STD' and popsrc= 'D' and consol= 'C' and curcd = 'USD'; 
  * retrieve accounting information as early as 1960 to calculate cash flow volatility over the past 20 years;
  by gvkey datadate;
run;

proc sql;
  create table cst as 
  select a.*, b.lpermno as permno, b.lpermco as permco, b.linktype, b.linkprim, b.liid
  from cst as a, crspcc.ccmxpf_linktable as b
  where a.gvkey = b.gvkey and linktype in ("LC", "LN", "LU", "LX", "LD", "LS") and
        usedflag in (1) and (datadate >= linkdt or linkdt = .B) and (datadate <= linkenddt or linkenddt = .E)
  order by gvkey, datadate, lpermno, lpermco, linkdt, linkenddt; 
quit; 

proc sort data = cst; by gvkey permco permno fyear descending datadate linktype descending linkprim liid;

data cst; set cst; by gvkey permco permno fyear descending datadate linktype descending linkprim liid;
  if first.fyear;
  keep gvkey permco permno fyear datadate sich naicsh;
run; 

proc sort data=crsp.stocknames(keep=permno ncusip cusip ticker namedt nameenddt shrcd exchcd siccd where=(not missing(ncusip))) 
  out=permnos nodupkey; by permno namedt nameenddt;
run;

proc sql;
  create table cst as
  select a.*, b.siccd, b.namedt, b.nameenddt
  from cst as a left join permnos as b
  on a.permno = b.permno and b.namedt <= a.datadate <= nameenddt;
quit;

proc sort data = cst nodupkey; by permno namedt nameenddt;

data cst; set cst; 
  if sich = . and siccd ne 0 then sich = siccd;
  sic2 = int(sich/100);
  sic3 = int(sich/10);
  keep gvkey permco permno namedt nameenddt sich sic2 sic3 naicsh siccd;
run; 

proc sql;
  create table cst as
  select a.*, b.ff48, b.ff48ind
  from cst as a left join root.ff48 as b
  on ff1 <= sich <= ff2;
quit;

proc sql;
  create table cst as
  select a.*, b.ff12, b.ff12ind
  from cst as a left join root.ff12 as b
  on ff1 <= sich <= ff2;
quit;

proc sql;
  create table crsp_ret as 
  select a.*, b.ret, b.date, abs(b.prc)*b.shrout as me
  from cst as a, crsp.dsf as b
  where a.permno = b.permno and a.namedt <= b.date <= a.nameenddt;
quit;

proc sort nodupkey; by permno descending date;

data crsp_ret2; set crsp_ret; by permno descending date; 
  set crsp_ret (firstobs=2 keep=permno date me rename=(permno=permno2 date=date2 me=me_lag));
  if permno ne permno2 or intck('month', date2, date) not in (0, 1) then me_lag = .;
run;

proc sort data = crsp_ret2; by ff48 date;

proc means noprint; by ff48 date;
  var ret; weight me_lag; where me_lag ne .;
  output out = returns_ff48 (drop=_type_ _freq_) mean = ret_ff48;

proc sort data = crsp_ret2; by sich date;

proc means noprint; by sich date;
  var ret; weight me_lag; where me_lag ne .;
  output out = returns_sic4 (drop=_type_ _freq_) mean = ret_sic4;

proc sort data = crsp_ret2; by sic3 date;

proc means noprint; by sic3 date;
  var ret; weight me_lag; where me_lag ne .;
  output out = returns_sic3 (drop=_type_ _freq_) mean = ret_sic3;

proc sort data = crsp_ret2; by sic2 date;

proc means noprint; by sic2 date;
  var ret; weight me_lag; where me_lag ne .;
  output out = returns_sic2 (drop=_type_ _freq_) mean = ret_sic2;
run;

************************************************* Compute industry-adjusted returns *************************************************;





data stock_meetings3; set stock_meetings2a stock_meetings2b;
  if -280 <= td_count <= 400; *****************************;

proc sql;
  create table stock_meetings3 as
  select a.*, a.ret-b.ret_ff48 as abnret_ff48
  from stock_meetings3 as a left join returns_ff48 as b
  on a.date = b.date and a.ff48 = b.ff48;
quit;

proc sql;
  create table stock_meetings3 as
  select a.*, a.ret-b.ret_sic4 as abnret_sic4
  from stock_meetings3 as a left join returns_sic4 as b
  on a.date = b.date and a.sich = b.sich;
quit;

proc sql;
  create table stock_meetings3 as
  select a.*, a.ret-b.ret_sic3 as abnret_sic3
  from stock_meetings3 as a left join returns_sic3 as b
  on a.date = b.date and int(a.sich/10) = b.sic3;
quit;

proc sql;
  create table stock_meetings3 as
  select a.*, a.ret-b.ret_sic2 as abnret_sic2
  from stock_meetings3 as a left join returns_sic2 as b
  on a.date = b.date and int(a.sich/100) = b.sic2;
quit;

proc sql;
  create table stock_meetings3 as
  select a.*, b.dgtw_xret, b.dgtw_vwret
  from stock_meetings3 as a left join temp.dgtw_returns_daily as b
  on a.permno = b.permno and a.date = b.date and b.dgtw_xret ne .;
quit;

proc sort; by permno meetingdate;

data stock_meetings3; merge stock_meetings3 stock_betas; by permno meetingdate;
  if num_trdng_days_beta >= 60 then ret_capm = ret-rf-beta*mktrf; 
  if num_trdng_days_beta >= 60 then retff3 = ret-rf-betam3*mktrf-betah3*hml-betas3*smb; 
  if num_trdng_days_beta >= 60 then retff4 = ret-rf-betam4*mktrf-betah4*hml-betas4*smb-betau4*umd; 
  abs_ret_mktadj = abs(ret_mktadj);
  abs_retff4 = abs(retff4);
  abs_dgtw_xret = abs(dgtw_xret);

proc means data = stock_meetings3 n mean median p25 p75;
run;

proc sort data = stock_meetings3 nodupkey; by permno meetingdate date; run;

proc means data = stock_meetings3 noprint; by permno meetingdate;
  var retx ret_capm retff3 retff4 ret_mktadj dgtw_xret; where -1 <= td_count <= 3;
  output out = car5d sum = car5d car5d_capm car5d_ff3 car5d_ff4 car5d_m car5d_dgtw;

proc means data = stock_meetings3 noprint; by permno meetingdate;
  var retx ret_capm retff3 retff4 ret_mktadj dgtw_xret; where -1 <= td_count <= 5;
  output out = car7d sum = car7d car7d_capm car7d_ff3 car7d_ff4 car7d_m car7d_dgtw;

proc means data = stock_meetings3 noprint; by permno meetingdate num_trdng_days_beta;
  var retx ret_capm retff3 retff4 ret_mktadj dgtw_xret abs_ret_mktadj abs_retff4 abs_dgtw_xret abnret_ff48 abnret_sic4 abnret_sic3 abnret_sic2; where -1 <= td_count <= 10;
  output out = car12d sum = car12d car12d_capm car12d_ff3 car12d_ff4 car12d_m car12d_dgtw abs_car12d_m abs_car12d_ff4 abs_car12d_dgtw car12d_ff48 car12d_sic4 car12d_sic3 car12d_sic2 min(date) = st_date12 max(date)=end_date12;

proc means data = stock_meetings3 noprint; by permno meetingdate;
  var retx ret_capm retff3 retff4 ret_mktadj dgtw_xret; where 1 <= td_count <= 21;
  output out = car21d sum = car21d car21d_capm car21d_ff3 car21d_ff4 car21d_m car21d_dgtw;

proc means data = stock_meetings3 noprint; by permno meetingdate num_trdng_days_beta;
  var retx ret_capm retff3 retff4 ret_mktadj dgtw_xret abs_ret_mktadj abs_retff4 abs_dgtw_xret; where 1 <= td_count <= 63;
  output out = car63d sum = car63d car63d_capm car63d_ff3 car63d_ff4 car63d_m car63d_dgtw abs_car63d_m abs_car63d_ff4 abs_car63d_dgtw n(retx) = num_63d;

proc means data = stock_meetings3 noprint; by permno meetingdate num_trdng_days_beta;
  var retx ret_capm retff3 retff4 ret_mktadj dgtw_xret abs_ret_mktadj abs_retff4 abs_dgtw_xret; where 1 <= td_count <= 126;
  output out = car126d sum = car126d car126d_capm car126d_ff3 car126d_ff4 car126d_m car126d_dgtw abs_car126d_m abs_car126d_ff4 abs_car126d_dgtw; 

proc means data = stock_meetings3 noprint; by permno meetingdate num_trdng_days_beta;
  var retx ret_capm retff3 retff4 ret_mktadj dgtw_xret; where 1 <= td_count <= 252;
  output out = car252d sum = car252d car252d_capm car252d_ff3 car252d_ff4 car252d_m car252d_dgtw;

proc means data = stock_meetings3 noprint; by permno meetingdate num_trdng_days_beta;
  var retx ret_capm retff3 retff4 ret_mktadj dgtw_xret; where 1 <= td_count <= 378;
  output out = car378d sum = car378d car378d_capm car378d_ff3 car378d_ff4 car378d_m car378d_dgtw;

proc means data = stock_meetings3 noprint; by permno meetingdate num_trdng_days_beta;
  var retx ret_capm retff3 retff4 ret_mktadj dgtw_xret; where -11 <= td_count < -1;
  output out = car_pr10d sum = car_pr10d car_pr10d_capm car_pr10d_ff3 car_pr10d_ff4 car_pr10d_m car_pr10d_dgtw;

proc means data = stock_meetings3 noprint; by permno meetingdate num_trdng_days_beta;
  var retx ret_mktadj; where -252-1 <= td_count < -1;
  output out = car_pr252d sum = car_pr252d car_pr252d_m;

proc means data = stock_meetings3 noprint; by permno meetingdate num_trdng_days_beta;
  var retx ret_mktadj; where -252-11 <= td_count < -11;
  output out = car_pr11_252d sum = car_pr11_252d car_pr11_pr252d_m;

data temp.meetings_car_permno; merge price_pr2 car12d car5d car7d car21d car63d car126d car252d car378d car_pr10d car_pr252d car_pr11_252d; by permno meetingdate;
  format meetingdate st_date12 end_date12 date9.;
  drop _type_ _freq_;
run;

